/*
*	(*^。^*) TFrameWork License (*^。^*)
*/

/*
 *  Title :  
 *          
 *  Description :  
 *          
 *          
 *  Date : 
 *
 *  Author : DengPing
 *
 *  Modify : 
 */

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

namespace TFrameWork.Module.ActionEditor
{
    public abstract class CommonEventItemStyle : TrackItemStyleBase
    {
        protected override string eventFullName => "CommonEventItem.uxml";

        public abstract Color eventColor { get; }

        protected ChildTrackBase parentChildTrack;

        #region Component

        protected VisualElement ClipContent;
        protected Label Name;

        protected VisualElement Exceed;
        protected Label ExceedName;

        #endregion

        /// <summary>
        /// Audio真实帧数
        /// </summary>
        public abstract int RealLenth { get; }


        private bool _isInit = false;

        public void InitComponent(ChildTrackBase parent)
        {
            this.parentChildTrack = parent;
            if (!_isInit)
            {
                root = ActionEditorUtility.GetStyleSheet<VisualTreeAsset>(eventFullName).Instantiate().Query()
                    .ToList()[1];
                root.style.backgroundColor = eventColor;
                ClipContent = root.Q(nameof(ClipContent));
                Name = root.Q<Label>(nameof(Name));
                Exceed = root.Q(nameof(Exceed));
                ExceedName = root.Q<Label>(nameof(ExceedName));
                this.parentChildTrack.AddContent(this);

                InitLeftRightDrag();
                //左右的拖动操作
                LeftPoint.RegisterCallback<MouseDownEvent>(LeftPointMouseDown);
                LeftPoint.RegisterCallback<MouseUpEvent>(LeftPointMouseUp);
                LeftPoint.RegisterCallback<MouseMoveEvent>(LeftPointMouseMove);

                RightPoint.RegisterCallback<MouseDownEvent>(RightPointMouseDown);
                RightPoint.RegisterCallback<MouseUpEvent>(RightPointMouseUp);
                RightPoint.RegisterCallback<MouseMoveEvent>(RightPointMouseMove);

                root.RegisterCallback<MouseDownEvent>(RootMouseDown);
                root.RegisterCallback<MouseUpEvent>(RootMouseUp);
                root.RegisterCallback<MouseMoveEvent>(RootMouseMove);

                // 创建右键菜单
                var menu = new ContextualMenuManipulator(evt =>
                {
                    //_parent.addState = DropdownMenuAction.Status.Disabled;
                    evt.menu.AppendAction("删除", DeleteEvent, DropdownMenuAction.AlwaysEnabled);
                });
                root.AddManipulator(menu);

                _isInit = true;
            }

            ResetView();
        }

        private void DeleteEvent(DropdownMenuAction obj)
        {
            parentChildTrack.DeleteEvent(this);
        }

        #region 拖动操作

        //是否拖拽
        private bool mouseDrag = false;
        private bool drationLeftDrag = false;
        private bool drationRightDrag = false;

        private float movePositionX = -1;
        private float drationOffset = 0;

        private void LeftPointMouseDown(MouseDownEvent evt)
        {
            if (mouseDrag) return;
            movePositionX = -1;
            ActionEditor.Instance.MouseUpEvent += LeftPointMouseUp;
            ActionEditor.Instance.MouseMoveEvent += LeftPointMouseMove;
            ActionEditor.Instance.MouseOutEvent += LeftPointMouseOut;
            drationLeftDrag = true;
        }

        private void LeftPointMouseUp(MouseUpEvent evt)
        {
            ActionEditor.Instance.MouseUpEvent -= LeftPointMouseUp;
            ActionEditor.Instance.MouseMoveEvent -= LeftPointMouseMove;
            ActionEditor.Instance.MouseOutEvent -= LeftPointMouseOut;
            if (drationLeftDrag) ApplayDurationMove(true);
            drationLeftDrag = false;
        }

        private void LeftPointMouseMove(MouseMoveEvent evt)
        {
            if (drationLeftDrag)
            {
                var localPosition = parentChildTrack.trackEventContent.WorldToLocal(evt.mousePosition);
                movePositionX = localPosition.x;

                float size = 1;
                var currentIndex = movePositionX / ActionEditor.Instance.actionEditorConfig.frameUnitWidth;
                if (currentIndex < 0)
                {
                    currentIndex = 0;
                }

                if (currentIndex > eventData.startIndex + eventData.durationIndex)
                {
                    size = 1;
                    currentIndex = eventData.startIndex + eventData.durationIndex - size;
                    movePositionX = currentIndex * ActionEditor.Instance.actionEditorConfig.frameUnitWidth;
                    return;
                }
                else
                {
                    size = eventData.startIndex + eventData.durationIndex - currentIndex;
                }

                var pos = root.transform.position;
                pos.x = movePositionX;
                root.transform.position = pos;
                ResetSize(size);
            }
        }

        private void LeftPointMouseOut(MouseOutEvent evt)
        {
            ActionEditor.Instance.MouseUpEvent -= LeftPointMouseUp;
            ActionEditor.Instance.MouseMoveEvent -= LeftPointMouseMove;
            ActionEditor.Instance.MouseOutEvent -= LeftPointMouseOut;
            if (drationLeftDrag) ApplayDurationMove(true);
            drationLeftDrag = false;
        }

        private void RightPointMouseDown(MouseDownEvent evt)
        {
            if (mouseDrag) return;
            movePositionX = -1;
            ActionEditor.Instance.MouseUpEvent += RightPointMouseUp;
            ActionEditor.Instance.MouseMoveEvent += RightPointMouseMove;
            ActionEditor.Instance.MouseOutEvent += RightPointMouseOut;
            drationRightDrag = true;
        }

        private void RightPointMouseUp(MouseUpEvent evt)
        {
            ActionEditor.Instance.MouseUpEvent -= RightPointMouseUp;
            ActionEditor.Instance.MouseMoveEvent -= RightPointMouseMove;
            ActionEditor.Instance.MouseOutEvent -= RightPointMouseOut;
            if (drationRightDrag) ApplayDurationMove(false);
            drationRightDrag = false;
        }

        private void RightPointMouseMove(MouseMoveEvent evt)
        {
            if (drationRightDrag)
            {
                var localPosition = parentChildTrack.trackEventContent.WorldToLocal(evt.mousePosition);
                movePositionX = localPosition.x;

                float size = 1;
                var currentIndex = movePositionX / ActionEditor.Instance.actionEditorConfig.frameUnitWidth;
                if (currentIndex < eventData.startIndex)
                {
                    size = 1;
                    currentIndex = eventData.startIndex + size;
                    movePositionX = currentIndex * ActionEditor.Instance.actionEditorConfig.frameUnitWidth;
                    return;
                }
                else
                {
                    size = currentIndex - eventData.startIndex;
                }

                var pos = root.transform.position;
                pos.x = eventData.startIndex * ActionEditor.Instance.actionEditorConfig.frameUnitWidth;
                root.transform.position = pos;
                ResetSize(size);
            }
        }

        private void RightPointMouseOut(MouseOutEvent evt)
        {
            ActionEditor.Instance.MouseUpEvent -= RightPointMouseUp;
            ActionEditor.Instance.MouseMoveEvent -= RightPointMouseMove;
            ActionEditor.Instance.MouseOutEvent -= RightPointMouseOut;
            if (drationRightDrag) ApplayDurationMove(false);
            drationRightDrag = false;
        }

        private void RootMouseDown(MouseDownEvent evt)
        {
            if (drationRightDrag || drationLeftDrag) return;
            Select();
            var localPosition = parentChildTrack.trackEventContent.WorldToLocal(evt.mousePosition);
            drationOffset = root.WorldToLocal(evt.mousePosition).x;
            movePositionX = localPosition.x - drationOffset;
            ActionEditor.Instance.MouseUpEvent += RootMouseUp;
            ActionEditor.Instance.MouseMoveEvent += RootMouseMove;
            ActionEditor.Instance.MouseOutEvent += RootMouseOut;
            mouseDrag = true;
        }

        private void RootMouseUp(MouseUpEvent evt)
        {
            ActionEditor.Instance.MouseUpEvent -= RootMouseUp;
            ActionEditor.Instance.MouseMoveEvent -= RootMouseMove;
            ActionEditor.Instance.MouseOutEvent -= RootMouseOut;
            if (mouseDrag) ApplayMove();
            mouseDrag = false;

        }

        private void RootMouseMove(MouseMoveEvent evt)
        {
            if (mouseDrag)
            {
                var localPosition = parentChildTrack.trackEventContent.WorldToLocal(evt.mousePosition);
                movePositionX = localPosition.x - drationOffset;
                var pos = root.transform.position;
                pos.x = movePositionX;
                root.transform.position = pos;
            }
        }

        private void RootMouseOut(MouseOutEvent evt)
        {
            ActionEditor.Instance.MouseUpEvent -= RootMouseUp;
            ActionEditor.Instance.MouseMoveEvent -= RootMouseMove;
            ActionEditor.Instance.MouseOutEvent -= RootMouseOut;
            if (mouseDrag) ApplayMove();
            mouseDrag = false;
        }

        private void ApplayDurationMove(bool left)
        {
            if (movePositionX == -1) return;
            TUndo.RecordObject(eventData, "AudioEvent Size");
            if (left)
            {
                int size = 1;
                int targetIndex =
                    Mathf.RoundToInt(movePositionX / ActionEditor.Instance.actionEditorConfig.frameUnitWidth);
                if (targetIndex < 0)
                {
                    targetIndex = 0;
                }

                if (targetIndex > eventData.startIndex + eventData.durationIndex)
                {
                    size = 1;
                }
                else
                {
                    size = eventData.startIndex + eventData.durationIndex - targetIndex;
                }

                eventData.durationIndex = size;
                eventData.startIndex = targetIndex;
            }
            else
            {
                int size = 1;
                int targetIndex =
                    Mathf.RoundToInt(movePositionX / ActionEditor.Instance.actionEditorConfig.frameUnitWidth);
                if (targetIndex < eventData.startIndex)
                {
                    size = 1;
                }
                else
                {
                    size = targetIndex - eventData.startIndex;
                }

                eventData.durationIndex = size;
            }

            EditorUtility.SetDirty(ActionEditor.Instance.ActionData);
            ResetView();
        }

        private void ApplayMove()
        {
            if (movePositionX == -1) return;
            TUndo.RecordObject(eventData, "AudioEvent Move");
            int targetIndex = Mathf.RoundToInt(movePositionX / ActionEditor.Instance.actionEditorConfig.frameUnitWidth);
            eventData.startIndex = targetIndex;
            movePositionX = -1;
            EditorUtility.SetDirty(ActionEditor.Instance.ActionData);
            ResetView();
        }

        #endregion

        private void ResetSize(float size)
        {
            if (size <= RealLenth)
            {
                if (size < 1)
                {
                    size = 1;
                }

                ClipContent.style.width =
                    size * ActionEditor.Instance.actionEditorConfig.frameUnitWidth;

                Exceed.style.width = 0;
                ExceedName.text = "";
            }
            else
            {
                ClipContent.style.width = RealLenth * ActionEditor.Instance.actionEditorConfig.frameUnitWidth;


                Exceed.style.width = (size - RealLenth) *
                                     ActionEditor.Instance.actionEditorConfig.frameUnitWidth;
            }

            ShowContent();
        }

        public override void ResetView()
        {
            if (eventData.durationIndex <= RealLenth)
            {
                if (eventData.durationIndex < 1)
                {
                    eventData.durationIndex = 1;
                }

                ClipContent.style.width =
                    eventData.durationIndex * ActionEditor.Instance.actionEditorConfig.frameUnitWidth;

                Exceed.style.width = 0;
                ExceedName.text = "";
            }
            else
            {
                ClipContent.style.width = RealLenth * ActionEditor.Instance.actionEditorConfig.frameUnitWidth;
                Exceed.style.width = (eventData.durationIndex - RealLenth) *
                                     ActionEditor.Instance.actionEditorConfig.frameUnitWidth;
            }

            ShowContent();

            var pos = root.transform.position;
            pos.x = eventData.startIndex * ActionEditor.Instance.actionEditorConfig.frameUnitWidth;
            root.transform.position = pos;
        }


        /// <summary>
        /// 内容展示
        /// </summary>
        public virtual void ShowContent()
        {

        }
    }
}
